package org.termine.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

public class Xml {

	public static InputStream toXCalXml(List<InputStream> appointments) throws Exception {
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		XMLOutputFactory xmlOutFactory = XMLOutputFactory.newFactory();
		XMLEventWriter xmlEventWriter = xmlOutFactory.createXMLEventWriter(outputStream);
		XMLEventFactory xmlEventFactory = XMLEventFactory.newFactory();

		xmlEventWriter.add(xmlEventFactory.createStartDocument("UTF-8", "1.0"));
		Attribute iCalAttribute = xmlEventFactory.createAttribute("xmlns",
				"urn:ietf:params:xml:ns:icalendar-2.0");
		List<Attribute> iCalAttributeList = Arrays.asList(iCalAttribute);
		StartElement iCalElement = xmlEventFactory.createStartElement("", null, "icalendar",
				iCalAttributeList.iterator(), null);
		xmlEventWriter.add(iCalElement);

		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "vcalendar"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "properties"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "calscale"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "text"));
		xmlEventWriter.add(xmlEventFactory.createCharacters("GREGORIAN"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "text"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "calscale"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "prodid"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "text"));
		xmlEventWriter.add(xmlEventFactory.createCharacters("termine"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "text"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "prodid"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "version"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "text"));
		xmlEventWriter.add(xmlEventFactory.createCharacters("2.0"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "text"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "version"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "properties"));
		xmlEventWriter.add(xmlEventFactory.createStartElement("", null, "components"));

		XMLInputFactory xmlInFactory = XMLInputFactory.newFactory();
		for (int i = 0; i < appointments.size(); i++) {
			XMLEventReader xmlEventReader = xmlInFactory.createXMLEventReader(appointments.get(i));
			XMLEvent event = xmlEventReader.nextEvent();

			while (event.getEventType() != XMLEvent.START_ELEMENT) {
				event = xmlEventReader.nextEvent();
			}

			do {
				xmlEventWriter.add(event);
				event = xmlEventReader.nextEvent();
			} while (event.getEventType() != XMLEvent.END_DOCUMENT);

			xmlEventReader.close();
		}

		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "components"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "vcalendar"));
		xmlEventWriter.add(xmlEventFactory.createEndElement("", null, "icalendar"));
		xmlEventWriter.add(xmlEventFactory.createEndDocument());

		xmlEventWriter.close();
		return new ByteArrayInputStream(outputStream.toByteArray());
	}

	public static InputStream stringToXmlInputStream(String string) throws Exception {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(new InputSource(new StringReader(string)));
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		Source xmlSource = new DOMSource(document);
		Result outputTarget = new StreamResult(outputStream);
		TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
		return new ByteArrayInputStream(outputStream.toByteArray());
	}

}
